/**
 * 2016，thor.com，all rights reserved。
 * 
 * Project：		palmmall-core
 * Filename：	AStatementServiceImpl.java
 * Created：		2016年7月31日
 * Creator：		wolv
 */
package com.thor.palmmall.rest.statement;

import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;

import com.thor.commons.entity.BeanOperateInfo;
import com.thor.commons.entity.BeanToOperateInfoConverter;
import com.thor.commons.entity.OperateInfo;
import com.thor.commons.entity.UCN;
import com.thor.commons.exception.ThorServiceException;
import com.thor.commons.util.Assert;
import com.thor.commons.util.ConverterUtil;
import com.thor.palmmall.api.elecharges.PayMethod;
import com.thor.palmmall.api.pay.alipay.MutiChannelAlipayService;
import com.thor.palmmall.api.pay.chinapay.ChinaPayment;
import com.thor.palmmall.api.pay.chinapay.MutiChannelChinaPayService;
import com.thor.palmmall.api.pay.union.MutiChannelUnionPayService;
import com.thor.palmmall.api.pay.unionmch.MutiChannelUnionMchService;
import com.thor.palmmall.api.pay.wechat.MutiChannelWeChatService;
import com.thor.palmmall.api.pay.wechat.entity.RsPaySignature;
import com.thor.palmmall.api.pay.wechat.entity.WechatUnifiedOrder;
import com.thor.palmmall.api.statement.AStatementPayBill;
import com.thor.palmmall.api.statement.AStatementPayBillDetail;
import com.thor.palmmall.api.statement.AStatementPayBillState;
import com.thor.palmmall.api.statement.StatementService;
import com.thor.palmmall.rest.brand.ABizType;
import com.thor.palmmall.rest.brand.converter.ABizTypeConverter;
import com.thor.palmmall.rest.statement.converter.AStatementConverter;
import com.thor.palmmall.rest.statement.converter.AStatementQueryResultConverter;
import com.thor.palmmall.rest.statement.converter.SBuildingsParamConverter;
import com.thor.palmmall.rest.statement.converter.SFloorsParamConverter;
import com.thor.palmmall.rest.statement.converter.SQueryByContractParamConverter;
import com.thor.palmmall.rest.statement.converter.SQueryByStoreParamConverter;
import com.thor.palmmall.spi.basic.SBasicService;
import com.thor.palmmall.spi.brand.SBizType;
import com.thor.palmmall.spi.common.SResponse;
import com.thor.palmmall.spi.statement.SStatement;
import com.thor.palmmall.spi.statement.SStatementQueryResult;
import com.thor.palmmall.spi.statement.SStatementService;
import com.thor.palmmall.util.billnumber.BillNumberTool;
import com.thor.palmmall.util.pay.ContextHolderUtils;
import com.thor.palmmall.util.pay.IpUtil;

/**
 * @author wolv
 *
 */
public class AStatementServiceImpl implements AStatementService {

  @Override
  public AStatement queryByContract(AQueryByContractParam param) throws ThorServiceException {
    SResponse<SStatement> sResponse = sStatementService
        .queryByContract(SQueryByContractParamConverter.getInstance().convert(param));
    if (sResponse.isSuccess())
      return AStatementConverter.getInstance().convert(sResponse.getBody());
    else
      throw new ThorServiceException(sResponse.getMessage());
  }

  @Override
  public AStatementQueryResult queryByStore(AQueryByStoreParam param) throws ThorServiceException {
    SResponse<SStatementQueryResult> sResponse = sStatementService
        .queryByStore(SQueryByStoreParamConverter.getInstance().convert(param));
    if (sResponse.isSuccess())
      return AStatementQueryResultConverter.getInstance().convert(sResponse.getBody());
    else
      throw new ThorServiceException(sResponse.getMessage());
  }

  @Override
  public List<ABizType> bizType(Boolean onlyUpper) throws ThorServiceException {
    SResponse<List<SBizType>> sResponse = sBasicService.bizType(onlyUpper);
    if (sResponse.isSuccess()) {
      return ConverterUtil.convert(sResponse.getBody(), ABizTypeConverter.getInstance());
    } else {
      throw new ThorServiceException(sResponse.getMessage());
    }
  }

  @Override
  public List<UCN> buildings(ABuildingsParam param) throws ThorServiceException {
    SResponse<List<UCN>> sResponse = sBasicService
        .buildings(SBuildingsParamConverter.getInstance().convert(param));
    if (sResponse.isSuccess()) {
      return sResponse.getBody();
    } else {
      throw new ThorServiceException(sResponse.getMessage());
    }
  }

  @Override
  public List<UCN> floors(AFloorsParam param) throws ThorServiceException {
    SResponse<List<UCN>> sResponse = sBasicService
        .floors(SFloorsParamConverter.getInstance().convert(param));
    if (sResponse.isSuccess()) {
      return sResponse.getBody();
    } else {
      throw new ThorServiceException(sResponse.getMessage());
    }
  }

  @Override
  public StatementPayResponse pay(AStatementPayParam param, BeanOperateInfo operInfo)
      throws Exception {
    Assert.assertArgumentNotNull(param, "param");
    Assert.assertArgumentNotNull(param.getChannel(), "param.channel");
    Assert.assertArgumentNotNull(param.getLines(), "param.lines");
    Assert.assertArgumentNotNull(param.getMethod(), "param.method");

    AStatementPayBill bill = statementPayService.getByBillNumber(param.getBillNumber());
    if (bill == null) {
      bill = new AStatementPayBill();
      ensurePayBill(bill, param, operInfo);
    }
    if (bill.getState().equals(AStatementPayBillState.PAID)
        || bill.getState().equals(AStatementPayBillState.FINISH)) {
      throw new ThorServiceException("单号={0}的收款单。已经支付或已经完成", param.getBillNumber());
    }

    StatementPayResponse resp = new StatementPayResponse();
    if (param.getMethod().equals(PayMethod.alipay)) {// 支付宝支付
      Map<String, String> alipayParam = createAlipayParam(bill);
      String alipayPayment = mutiChannelAlipayService.getTradePayRequestByChannel(alipayParam,
          param.getChannel().getContents());
      resp.setAlipayPayment(alipayPayment);
      bill.setAlipayPublicKey(param.getChannel().getContents().getPUBLIC_KEY());
    } else if (param.getMethod().equals(PayMethod.wechat)) {// 微信支付
      WechatUnifiedOrder request = createWeChatPayParam(bill);
      RsPaySignature signature = mutiChannelWechatService.unifiedOrder(request,
          param.getChannel().getContents());
      if (signature == null) {
        throw new ThorServiceException("微信支付凭证生成失败");
      }
      resp.setWxSignature(signature);
    } else if (param.getMethod().equals(PayMethod.unionpay)) {
      Map<String, String> unionPayParams = createUnionPayParam(bill);// 银联支付
      String unionPayTradeNo = mutiChannelUnionPayService.getUnionPayTradeNo(unionPayParams,
          param.getChannel().getContents());
      resp.setUnionPayment(unionPayTradeNo);
    } else if (param.getMethod().equals(PayMethod.unionmch)) {
      Map<String, String> unionMchParams = createUnionPayParam(bill);// 银联商务app支付
      String unionPayTradeNo = mutiChannelUnionMchService.getUnionMchPayTradeNo(unionMchParams,
          param.getChannel().getContents());
      resp.setUnionPayment(unionPayTradeNo);
    } else if (param.getMethod().equals(PayMethod.chinapay)) {
      Map<String, Object> chinaPayParams = createChinaPayParam(bill, param.getTranType());// 银联商务WEB支付
      ChinaPayment chinaPayment = mutiChannelChinaPayService.getChinaPayment(chinaPayParams,
          param.getChannel().getContents());
      resp.setChinaPayment(chinaPayment);

    } else {
      throw new ThorServiceException("暂不支持此支付方式");
    }
    resp.setBillNumber(bill.getBillNumber());
    return resp;
  }

  /**
   * 创建银联支付WEB支付参数
   * 
   * @param tranType
   *          交易参数
   * @param bill
   *          订单
   * @return
   */
  private Map<String, Object> createChinaPayParam(AStatementPayBill bill, TranType tranType) {

    Map<String, Object> unionPayParam = new LinkedHashMap<String, Object>();
    Date today = new Date(System.currentTimeMillis());
    unionPayParam.put("TranDate", new SimpleDateFormat("yyyyMMdd").format(today));
    unionPayParam.put("TranTime", new SimpleDateFormat("hhmmss").format(today));
    unionPayParam.put("MerOrderNo", bill.getBillNumber());
    unionPayParam.put("OrderAmt",
        bill.getAmount().multiply(new BigDecimal(100.00)).intValue() + "");
    unionPayParam.put("RemoteAddr", IpUtil.getIpAddr(ContextHolderUtils.getRequest()));
    List<AStatementPayBillDetail> details = bill.getDetails();
    if (details != null && !details.isEmpty()) {
      unionPayParam.put("CommodityMsg", bill.getDetails().get(0).getSubject().getName());
    } else {
      unionPayParam.put("CommodityMsg", "对账单缴款");
    }

    // 0001个人网银支付0002企业网银支付
    if (TranType.company == tranType) {
      unionPayParam.put("TranType", "0002");
    } else {
      unionPayParam.put("TranType", "0001");
    }
    return unionPayParam;
  }

  private void ensurePayBill(AStatementPayBill bill, AStatementPayParam param,
      BeanOperateInfo operInfo) throws ThorServiceException {
    bill.setActionTime(param.getPaymentDate());
    bill.setBillNumber(billNumberTool.nextBillNumber(AStatementPayBill.class.getSimpleName()));
    bill.setMethod(param.getMethod());
    bill.setRemark(param.getRemark());
    bill.setState(AStatementPayBillState.SUBMIT);
    bill.setPaymentType(param.getChannel().getPaymentType());
    bill.setDetails(param.getLines());
    bill.setAlipayPublicKey(param.getChannel().getContents().getPUBLIC_KEY());
    BigDecimal amount = new BigDecimal("0");
    for (AStatementPayBillDetail detail : param.getLines()) {
      if (detail.getUnpayedTotal() != null) {
        // 应缴=未缴+手续费
        BigDecimal shouldPay = detail.getUnpayedTotal().add(detail.getPoundage());
        amount = amount.add(shouldPay);
      }
    }
    bill.setCommissionCharge(param.getCommissionCharge());
    bill.setAmount(amount);
    bill.setVerifyFilePath(param.getChannel().getContents().getRootCertPath());
    bill.setSignCertType(param.getChannel().getContents().getSignCertType());
    bill.setSignFilePath(param.getChannel().getContents().getSignCertPath());
    bill.setSignFilePwd(param.getChannel().getContents().getSignCertPwd());
    String uuid = statementPayService.saveStatementPayBill(bill,
        BeanToOperateInfoConverter.getInstance().convert(operInfo));
    bill.setUuid(uuid);
  }

  public Map<String, String> createAlipayParam(AStatementPayBill param) {
    Map<String, String> aliPayParam = new LinkedHashMap<String, String>();
    aliPayParam.put("body", "租户缴款");
    aliPayParam.put("subject", "租户缴款");
    aliPayParam.put("out_trade_no", param.getBillNumber());
    aliPayParam.put("total_amount", param.getAmount().toString());
    aliPayParam.put("product_code", "QUICK_MSECURITY_PAY");
    return aliPayParam;
  }

  public WechatUnifiedOrder createWeChatPayParam(AStatementPayBill bill) {
    WechatUnifiedOrder request = new WechatUnifiedOrder();
    request.setBody("租户缴款");
    request.setDetail("租户缴款");
    request.setGoods_tag("租户缴款");
    request.setOut_trade_no(bill.getBillNumber());
    request.setFee_type("CNY");
    request.setTotal_fee(bill.getAmount().multiply(new BigDecimal(100.00)).intValue());
    request.setSpbill_create_ip(IpUtil.getIpAddr(ContextHolderUtils.getRequest()));
    return request;
  }

  private Map<String, String> createUnionPayParam(AStatementPayBill param) {
    Map<String, String> unionPayParam = new LinkedHashMap<String, String>();
    unionPayParam.put("txnTime",
        new SimpleDateFormat("yyyyMMddHHmmss").format(new Date(System.currentTimeMillis())));
    unionPayParam.put("orderId", param.getBillNumber());
    unionPayParam.put("txnAmt", param.getAmount().multiply(new BigDecimal(100.00)).intValue() + "");
    return unionPayParam;
  }

  @Override
  public void paynotify(String billNumber, String state, BeanOperateInfo operInfo)
      throws ThorServiceException {
    Assert.assertArgumentNotNull(billNumber, "billNumber");
    OperateInfo oi = BeanToOperateInfoConverter.getInstance().convert(operInfo);

    AStatementPayBill bill = statementPayService.getByBillNumber(billNumber);
    if (bill == null) {
      throw new ThorServiceException("找不到billNumber={0}的缴款单。", billNumber);
    }

    if (AStatementPayBillState.FINISH == bill.getState()) {
      return;
    }

    if ("PAID".equals(state)) {
      bill.setState(AStatementPayBillState.PAID);
    } else {
      bill.setState(AStatementPayBillState.FAILED);
    }
    statementPayService.saveStatementPayBill(bill, oi);
  }

  @Override
  public AStatementPayBill getStatementOrder(String billNumber) throws ThorServiceException {
    Assert.assertArgumentNotNull(billNumber, "billNumber");
    return statementPayService.getByBillNumber(billNumber);
  }

  @Override
  public void confirmStatementSubjects(List<String> accIds) throws ThorServiceException {
    Assert.assertArgumentNotNull(accIds, "accIds");
    SResponse<Void> sResponse = sStatementService.confirmStatementSubjects(accIds);
    if (!sResponse.isSuccess())
      throw new ThorServiceException(sResponse.getMessage());
  }

  @Autowired
  private SBasicService sBasicService;
  @Autowired
  private SStatementService sStatementService;

  @Autowired
  private StatementService statementPayService;

  @Autowired
  private BillNumberTool billNumberTool;

  @Autowired
  private MutiChannelAlipayService mutiChannelAlipayService;

  @Autowired
  private MutiChannelWeChatService mutiChannelWechatService;

  @Autowired
  private MutiChannelUnionPayService mutiChannelUnionPayService;

  @Autowired
  private MutiChannelUnionMchService mutiChannelUnionMchService;

  @Autowired
  private MutiChannelChinaPayService mutiChannelChinaPayService;

}
